﻿using System;
using System.Data;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Axiom;
using Axiom.Core;
using Axiom.Graphics;
using Axiom.Configuration;
using Axiom.Math;
using Axiom.Overlays;
using Axiom.Input;
using Axiom.Animating;
using Axiom.SceneManagers.Octree;
using Axiom.ParticleSystems;


namespace w4nted
{
    class Program
    {
        static void Main(string[] args)
        {
            axiom_engine_ test = new axiom_engine_();
            test.Run();
            test.net.StopNetwork();
        }
        
        class axiom_engine_ : axiom_engine
        {
            //Initialing of public variables
            #region Variables 
            TerrainSceneManager terrain;
            private float m_moveScale = 0, m_rotScale = 0, m_moveSpeed = 300, m_rotateSpeed = 36;
            private Vector2 m_rotateVector = new Vector2(0, 0);
            private Vector3 m_translateVector = new Vector3(0, 0, 0);
            internal SceneNode me_node;
            private Boolean first_run = true;
            private vektor_util u = new vektor_util();
            internal ParticleSystem laser;
            bool jump = false;
            DateTime timer;
            private int shoot_counter=0;
            private ShootManager shoot_manag = new ShootManager();
            internal  Netzwerk net = new Netzwerk();
            DateTime Shootfrequence = DateTime.Now;
            #endregion

            protected override void CreateScene()
            {
                SceneManager.AmbientLight = new ColorEx(1, 1, 1);

                //creates the robot and adds a SceneNode
                //me_entity = SceneManager.CreateEntity("Robot", "robot.mesh");
                me_node = SceneManager.RootSceneNode.CreateChildSceneNode("ME", new Vector3(0, 0, 0));
                //me_node.AttachObject(me_entity);w
                
                //me_camera_node = me_node.CreateChildSceneNode("camera_node", new Vector3(-100, 100, 0));
                //me_node.AddChild(me_camera_node);
               //me_AnimationState = me_entity.GetAnimationState("Walk");a
                // me_AnimationState.Loop = true;

                // loads terrain
                SceneManager.LoadWorldGeometry("Terrain.xml");

                Overlay sprite = OverlayManager.Instance.GetByName("overlay_sprite");
                sprite.ZOrder = 600;
                OverlayElementManager.Instance.GetElement("panle_Sprite").Left -= 20;
                OverlayElementManager.Instance.GetElement("panle_Sprite").Top -= 20;
                sprite.Show();

                // create a cool glowing green particle system
                laser = ParticleSystemManager.Instance.CreateSystem("GreenyNimbus", "ParticleSystems/Laser");
               // me_node.AttachObject(laser);

               // shoot = SceneManager.RootSceneNode.CreateChildSceneNode("Shoot");
                //shoot.AttachObject(laser);
                net.StartNetwork();

            }

            internal SceneNode gen_shoot(Vector3 start)
            {
                shoot_counter += 2;
                try { laser.ParentSceneNode.DetachAllObjects(); }
                catch { }
                finally { }

                SceneNode res = SceneManager.RootSceneNode.CreateChildSceneNode("Shoot"+shoot_counter,start);
                res.AttachObject(laser);
                return res;
            }

            protected override void FrameStarted(object source, FrameEventArgs e)
            {
                if (net.Shoots_recieved.Count > 0)
                {
                    Netzwerk.NetShoot ns = net.Shoots_recieved.Dequeue();

                    Shoot temp_shoot = new Shoot();
                    temp_shoot.start(new Vector3(ns.x, ns.y, ns.z), new Quaternion(ns.qw,ns.qx,ns.qy,ns.qz), this, SceneManager);
                    shoot_manag.add(temp_shoot);
                }
                Entity tmp_ent;
                SceneNode tmp_node;
                List<player> ll = new List<player>(net.playerliste);
                foreach (player p in ll)
                {
                    if (!p.created)
                    {
                        tmp_ent = SceneManager.CreateEntity("PlayerEntity" + p.host_ep.Address.GetAddressBytes()[3].ToString(), "robot.mesh");
                        tmp_node = SceneManager.RootSceneNode.CreateChildSceneNode("Player" + p.host_ep.Address.GetAddressBytes()[3].ToString());
                        SceneNode help_node = tmp_node.CreateChildSceneNode("PlayerRobot" + p.host_ep.Address.GetAddressBytes()[3].ToString());
                        help_node.AttachObject(tmp_ent);


                        help_node.Yaw(90);
                        
                        p.created = true;
                    }
                    else
                    {
                        tmp_node = SceneManager.GetSceneNode("Player" + p.host_ep.Address.GetAddressBytes()[3].ToString());
                    }
                    tmp_node.Position = p.position.ToVector3();
                    tmp_node.Orientation = p.orientation.ToQuanternion();
                }
            }

            protected override void CreateCamerainit(Camera m_camera, SceneManager m_sceneManager)
            {
                // Positions the camera
                m_camera.Position = new Vector3(-300, 200, 0);

                // defines where the camera looks at
                m_camera.LookAt(new Vector3(0, 125, 0));
                m_camera.Near = 5;
            }
   
            protected override void Input_handler(object source, FrameEventArgs e, InputReader m_inputReader, SceneManager m_sceneManager, Camera m_camera)
             {
                m_rotScale = m_rotateSpeed * e.TimeSinceLastFrame;
                terrain = (TerrainSceneManager)m_sceneManager;

                 #region Camera movement
                // Reset vectors
                m_rotateVector.x = m_translateVector.x = 0;
                m_rotateVector.y = m_translateVector.y = 0;
                m_translateVector.z = 0;

                // Move
                m_moveScale = m_moveSpeed * e.TimeSinceLastFrame;

                // Rotate
                m_rotScale = m_rotateSpeed * e.TimeSinceLastFrame;

                // Move forward and back
                if (m_inputReader.IsKeyPressed(KeyCodes.W) || m_inputReader.IsKeyPressed(KeyCodes.Up))
                    m_translateVector.z = -m_moveScale;
                else if (m_inputReader.IsKeyPressed(KeyCodes.S) || m_inputReader.IsKeyPressed(KeyCodes.Down))
                    m_translateVector.z = m_moveScale;

                // Move left and right
                if (m_inputReader.IsKeyPressed(KeyCodes.A))
                    m_translateVector.x = -m_moveScale;
                else if (m_inputReader.IsKeyPressed(KeyCodes.D))
                    m_translateVector.x = m_moveScale;

                // Move up and down
                if (m_inputReader.IsKeyPressed(KeyCodes.PageUp))
                    m_translateVector.y = m_moveScale;
                else if (m_inputReader.IsKeyPressed(KeyCodes.PageDown))
                    m_translateVector.y = -m_moveScale;

                // Rotate left and right
                if (m_inputReader.IsKeyPressed(KeyCodes.Left))
                    m_rotateVector.x = -m_rotScale;
                else if (m_inputReader.IsKeyPressed(KeyCodes.Right))
                    m_rotateVector.x = m_rotScale;

                // Right mouse button pressed
                if (m_inputReader.IsMousePressed(MouseButtons.Right))
                {
                    // Translate
                    m_translateVector.x += m_inputReader.RelativeMouseX * 0.13f;
                    m_translateVector.y -= m_inputReader.RelativeMouseY * 0.13f;
                }
                else
                {
                    // Apply mouse rotation
                    m_rotateVector.x += m_inputReader.RelativeMouseX * 0.13f;
                    m_rotateVector.y += m_inputReader.RelativeMouseY * 0.13f;
                }


                //jump
                if (m_inputReader.IsKeyPressed(KeyCodes.Space) && !jump)
                {
                    timer = DateTime.Now.AddMilliseconds(800);
                    jump = true;
                }


                // Apply changes
                me_node.Yaw(-m_rotateVector.x);
                //me_node.Pitch(-m_rotateVector.y);



                Vector3 move;
                Vector3 next_position;

                //Move Ego-Object
                move = u.TransformVectorToBasis(me_node.LocalAxes, m_translateVector);
                
                next_position = me_node.Position + move;
               
                #region Der Steigung Angepassten Geschwindigkeit

                if (jump == false)
                {
                    float steigung = terrain.GetHeightAt(next_position, 0) - me_node.Position.y;

                    //LogManager.Instance.Write("Steigung =  " + steigung);
                    /*
                    if (steigung > 0.1 && Math.Abs(steigung) < 3) move = move / (steigung);
                    if (steigung < -0.1 && Math.Abs(steigung)< 3) move = move * (Math.Abs(steigung));
                     */
                    if (Math.Abs(steigung) >= 10) move = move * 0;
                }
                
                #endregion
                
                me_node.Position += move;

                if (jump == true)
                {
                    int jumptime = timer.Millisecond - DateTime.Now.Millisecond;
                    if (jumptime >= 400)
                    {
                        me_node.Position = new Vector3(me_node.Position.x, terrain.GetHeightAt(me_node.Position, 0) + (800 - jumptime), me_node.Position.z);
                    } 
                    else if (jumptime >= 0)
                    {
                        me_node.Position = new Vector3(me_node.Position.x, terrain.GetHeightAt(me_node.Position, 0) + jumptime, me_node.Position.z);
                    }
                    else {jump = false;}
                }
                else
                {
                    me_node.Position = new Vector3(me_node.Position.x, terrain.GetHeightAt(me_node.Position, 0), me_node.Position.z);
                }


                if (first_run)
                {
                    m_camera.Orientation = me_node.Orientation;
                    first_run = false;
                }

                Vector3 dist = u.TransformVectorToBasis(me_node.LocalAxes, new Vector3(0, 20, 0));
                m_camera.Position = me_node.Position + new Vector3(dist.x, dist.y, dist.z);
                m_camera.Pitch(-m_rotateVector.y);
                m_camera.Yaw(-m_rotateVector.x);

                //m_camera.Position = new Vector3(0,me_node.Position.y + 20,0);
                //m_camera.MoveRelative(m_translateVector);

                #endregion Camera movement            

                 #region Shoot Actions

                if (m_inputReader.IsMousePressed(MouseButtons.Left) && Shootfrequence.CompareTo(DateTime.Now) < 0)
                {
                    Shoot temp_shoot = new Shoot();
                    temp_shoot.start(m_camera.Position, m_camera.Orientation, this,m_sceneManager);
                    shoot_manag.add(temp_shoot);
                    net.AddShoot(m_camera.Position, m_camera.Orientation);
                    Shootfrequence = DateTime.Now.AddMilliseconds(500);
                }

                shoot_manag.update();
                 #endregion 

                #region NetworkSync
                net.me.position.SetVector(me_node.Position);
                net.me.orientation.SetQuanternion(me_node.Orientation);
                #endregion
             }
        }
        
        class Shoot
            {
                TimeSpan remaining = new TimeSpan(0, 0, 5);
                Vector3 place;
                Quaternion or;
                SceneNode node;
                vektor_util ut =new vektor_util();
                public int counter = 0;
                SceneManager s;
                public void start(Vector3 start, Quaternion orientation,axiom_engine_ engine,SceneManager scenemanager)
                {
                    s = scenemanager;
                    place = new Vector3(start.x, start.y, start.z)-new Vector3(0,3,0);
                    or = orientation;
                    node = engine.gen_shoot(place);                    
                }
                public void update()
                {
                    node.Position += ut.TransformVectorToBasis(or.ToRotationMatrix(), new Vector3(0, 0, -20));
                    counter += 1;
                }
                public void destroy()
                {
                    node.DetachAllObjects();
                    node.RemoveAllChildren();
                    node.RemoveFromParent();
                    s.DestroySceneNode(node.Name);
                }
            }

        class ShootManager
            {
                List<Shoot> liste = new List<Shoot>();
                public void update()
                {
                    foreach (Shoot item in liste)
                    {
                        item.update();
                        if (item.counter > 50)
                        {
                            item.destroy();
                            remv(item);
                            break;
                        }
                    }
                }
                public void add(Shoot shoot)
                {
                    liste.Add(shoot);
                }
                public void remv(Shoot shoot)
                {
                    liste.Remove(shoot);
                }
            } 
    }
}
